﻿using System;
using System.Linq;
using Babushka.GameModels.Tiles;
using Babushka.Resources;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Babushka.GameModels
{
    class Babushka : ICharacter
    {
        public const int G = 1;
        public const int ChangeFrameSkip = 60;
        public const int DefaultJumpLength = 10;
        public const int MaxFallSpeed = 10;

        KeyboardState lastState;
        int size;
        int health;
        int sizeChangeTime;
        int newSize;

        int jumpLeft;

        int fallSpeed;

        private Vector2 position;

        public Babushka(Vector2 startPosition)
        {
            Position = startPosition;
        }

        public delegate void HealthChangedDelegate(Babushka sender);
        public event HealthChangedDelegate HealthChanged;
        public int Height
        {
            get
            {
                return Tiles.Tile.TileSize + (Tiles.Tile.TileSize * size / 2);
            }
        }
        public int Width
        {
            get
            {
                return (Tiles.Tile.TileSize / 2) + (4 * size);
            }
        }
        public int Health
        {
            get
            {
                return health;
            }
            set
            {
                HealthChanged(this);
                health = value;
            }
        }
        public int MaxHealth
        {
            get
            {
                return 3;
            }
        }
        public bool IsInfiniteHealth
        {
            get
            {
                return false;
            }
        }
        public Vector2 Position
        {
            get
            {
                return position;
            }
            set
            {
                position = value;
            }
        }
        public Rectangle BoundingBox 
        {
            get
            {
                return new Rectangle((int)Position.X - Width / 2, (int)Position.Y - Height, Width, Height);
            }
        }
        public int Size
        {
            get
            {
                return size;
            }
        }
        public int FallSpeed
        {
            get
            {
                return fallSpeed;
            }
            set
            {
                fallSpeed = Math.Max(Math.Min(value, MaxFallSpeed), 0);
            }
        }
        public Rectangle GetBoundingBox(Vector2 pos)
        {
            return new Rectangle((int)pos.X - Width / 2, (int)pos.Y - Height, Width, Height);
        }

        public void Update(Level lvl)
        {
            if (sizeChangeTime > 0)
            {
                sizeChangeTime--;
                if (sizeChangeTime <= 0)
                {
                    sizeChangeTime = 0;
                    size = newSize;
                }
            }

            GravityControl(lvl);
            KeyboardState state = Keyboard.GetState();
            bool mLeft = state.IsKeyDown(ActionKeys.MoveLeft);
            bool mRight = state.IsKeyDown(ActionKeys.MoveRight);

            int movement = mRight.CompareTo(mLeft);
            switch (movement)
            {
                case -1: position.X -= 1; break;//Move Left
                case 1: position.X += 1; break; //Move right
                case 0: break; //Do nothing
            }

            if (state.IsKeyDown(ActionKeys.Jump) && !IsInAir(lvl))
                Jump();
            Console.WriteLine(jumpLeft);
        }
  
        private void GravityControl(Level lvl)
        {
            if (jumpLeft > 0)
            {
                position.Y -= (jumpLeft--);
            }
            else if (IsInAir(lvl))
            {
                FallSpeed += G;
                Position = new Vector2
                {
                    X = Position.X,
                    Y = Position.Y + FallSpeed
                };
                if (!IsInAir(lvl))
                    position.Y -= position.Y % Tile.TileSize;
            }
            else
            {
                position.Y -= position.Y % Tile.TileSize;
            }
        }

        public bool IsInAir(Level lvl)
        {
            var y = (int)Position.Y / Tile.TileSize;
            var x = (int)Position.X / Tile.TileSize;
            var tileBoundingBox = new Rectangle()
            {
                X = x * Tile.TileSize,
                Y = y * Tile.TileSize,
                Width = Tile.TileSize,
                Height = Tile.TileSize
            };
            return lvl[x, y] == null || !tileBoundingBox.Intersects(BoundingBox);
        }

        public void Draw()
        {
            Game1.SpriteBatch.Draw(Resources.Graphics.Babushkas[Size], BoundingBox, Color.White);
        }

        public void Shrink()
        {
            newSize = Size - 1;
            sizeChangeTime = ChangeFrameSkip;
        }

        public void Expend()
        {
            newSize = Size + 1;
            sizeChangeTime = ChangeFrameSkip;
        }

        public void Jump(int jumpLength = DefaultJumpLength)
        {
            if (this.jumpLeft <= 0)
                this.jumpLeft = jumpLength;
        }
        public override string ToString()
        {
            return jumpLeft.ToString();
        }
    }
}